-
Notifications
You must be signed in to change notification settings - Fork 4
Feature/summit sponsor pages #755
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
…opup Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
…750) * feat: page modules generic component, test, adjusting formik inputs Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com> * fix: add implementation for pages modules on sponsor global Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com> --------- Signed-off-by: Tomás Castillo <tcastilloboireau@gmail.com>
📝 WalkthroughWalkthroughAdds sponsor pages feature: Redux actions/reducer, list and cloning UI, page-template module components/tests, form input tweaks, routing/menu entry, constants, translations, and store wiring. Changes
Sequence DiagramssequenceDiagram
participant User
participant SponsorPagesListPage
participant Redux
participant API
participant Store
User->>SponsorPagesListPage: Mount / request pages
SponsorPagesListPage->>Redux: dispatch getSponsorPages(filters)
Redux->>Redux: dispatch startLoading
Redux->>API: GET /sponsor_pages with params
API-->>Redux: pages response
Redux->>Store: dispatch RECEIVE_SPONSOR_PAGES (normalize)
Store-->>SponsorPagesListPage: updated props
Redux->>Redux: dispatch stopLoading
SponsorPagesListPage-->>User: render pages table
sequenceDiagram
participant User
participant GlobalPagePopup
participant SelectPagesDialog
participant SelectSponsorshipsDialog
participant Redux
participant API
User->>GlobalPagePopup: open popup
GlobalPagePopup->>SelectPagesDialog: show templates stage
User->>SelectPagesDialog: select templates, click Add
SelectPagesDialog-->>GlobalPagePopup: onSelectTemplates(ids)
GlobalPagePopup->>SelectSponsorshipsDialog: show sponsorships stage
User->>SelectSponsorshipsDialog: choose sponsorships, click Save
SelectSponsorshipsDialog-->>GlobalPagePopup: onSave(tiers)
GlobalPagePopup->>Redux: dispatch cloneGlobalPage(templateIds, sponsorIds/tiering)
Redux->>API: POST /sponsor_pages/clone with payload
API-->>Redux: success
Redux->>Redux: dispatch GLOBAL_PAGE_CLONED and getSponsorForms
Redux-->>GlobalPagePopup: success
GlobalPagePopup-->>User: show snackbar, close popup
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 3✅ Passed checks (3 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. 🧹 Recent nitpick comments
📜 Recent review detailsConfiguration used: defaults Review profile: CHILL Plan: Pro 📒 Files selected for processing (1)
🧰 Additional context used🪛 dotenv-linter (4.0.0).env.example[warning] 20-20: [UnorderedKey] The SPONSOR_PAGES_SCOPES key should go before the SPONSOR_USERS_API_SCOPES key (UnorderedKey) ⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
✏️ Tip: You can disable this entire section by setting Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 14
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
src/components/mui/formik-inputs/mui-formik-datepicker.js (1)
8-8:propsis undefined — this will throw a ReferenceError at runtime.The component destructures only
{ name, label, required }but line 40 spreads{...props}which doesn't exist in scope.Additionally,
marginis not a valid prop on MUI'sDatePickercomponent — it should remain inslotProps.textField.🐛 Proposed fix
-const MuiFormikDatepicker = ({ name, label, required }) => { +const MuiFormikDatepicker = ({ name, label, required, ...props }) => {And move
marginback intoslotProps.textField:textField: { name, label: required ? requiredLabel : label, error: meta.touched && Boolean(meta.error), helperText: meta.touched && meta.error, - fullWidth: true + fullWidth: true, + margin: "normal" },}} - margin="normal" // eslint-disable-next-line react/jsx-props-no-spreading {...props}Also applies to: 38-40
src/components/mui/formik-inputs/mui-formik-select.js (1)
74-79: Missing PropTypes definition forlabelprop.The component accepts a
labelprop (line 16) but it's not declared in PropTypes.Suggested fix
MuiFormikSelect.propTypes = { name: PropTypes.string.isRequired, children: PropTypes.node.isRequired, placeholder: PropTypes.string, - isClearable: PropTypes.bool + isClearable: PropTypes.bool, + label: PropTypes.string };
🤖 Fix all issues with AI agents
In `@src/actions/sponsor-pages-actions.js`:
- Around line 95-133: The cloneGlobalPage action dispatches startLoading() but
never dispatches stopLoading(), leaving the loading state active; update
cloneGlobalPage to dispatch stopLoading() in both the success path (before/after
dispatching getSponsorForms() and snackbarSuccessHandler) and in the
catch/failure path (before handling errors via snackbarErrorHandler) so that
stopLoading() is always called regardless of postRequest resolving or rejecting;
locate the postRequest(...) promise chain in cloneGlobalPage and add
dispatch(stopLoading()) in both the .then and .catch handlers (or use finally)
to guarantee loading is cleared.
- Around line 124-125: The call to getSponsorForms() inside the cloneGlobalPage
promise chain will throw because getSponsorForms is not imported; fix this by
adding an import for getSponsorForms at the top of the file from the module that
exports it (the same module where sponsor form actions live) and keep the
dispatch(getSponsorForms()) call, or if the intent was to refresh sponsor pages
instead, replace that call with the correct exported action (e.g.,
dispatch(getSponsorPages()) )—ensure the chosen function is imported and
referenced (symbols: getSponsorForms, cloneGlobalPage, dispatch).
In `@src/components/mui/formik-inputs/mui-formik-select.js`:
- Around line 34-45: The label can overlap the placeholder because hasValue only
reflects a selected value; update the hasValue logic in the component that
renders InputLabel and Select so it treats a provided placeholder (and
displayEmpty=true) as a value — e.g., compute hasValue = Boolean(field.value) ||
(displayEmpty && Boolean(placeholder)) — then continue using hasValue for
InputLabel's shrink and Select's notched props (symbols: InputLabel, Select,
hasValue, placeholder, displayEmpty, field).
In `@src/components/mui/formik-inputs/mui-formik-upload.js`:
- Line 65: Remove the debug console.log in the UploadFormik component (the line
logging "CHJECK RESPONSE" in mui-formik-upload.js); delete that console.log
statement (or replace it with a proper logger call without the typo if
intentional) so no stray debug output remains in the upload handling code.
- Line 16: Remove the debug console.log statement currently logging "images: "
and field.value inside the MuiFormikUpload component; delete the line
console.log("images: ", field.value) (or replace it with a proper debug-level
logger if persistent logging is required) so no console output remains in
production.
- Around line 93-101: The canAddMore function references mediaType.is_editable
but mediaType lacks that property; update the mediaType object used by this
component (the mediaType declaration near the top of mui-formik-upload.js) to
include is_editable: true or derive it from props, so canAddMore correctly
evaluates editable media types; ensure changes touch the mediaType definition
(not canAddMore) and keep the singleFile and field.value logic intact.
In `@src/layouts/sponsor-layout.js`:
- Line 28: The import for the React component is using camelCase; change the
import identifier from sponsorPagesListPage to PascalCase SponsorPagesListPage
and update all places where sponsorPagesListPage is referenced (e.g., the
component usage currently referencing it) to use SponsorPagesListPage so the
import and usage match the React component naming convention.
In `@src/pages/sponsors-global/page-templates/page-template-modules-form.js`:
- Around line 182-193: InputLabel's htmlFor is incorrectly targeting
buildFieldName("max_file_size") while the actual form control is
MuiFormikTextField with name buildFieldName("description"); update the
InputLabel so htmlFor uses buildFieldName("description") to match the
MuiFormikTextField name and restore proper accessibility (locate the InputLabel
and adjust the buildFieldName argument from "max_file_size" to "description").
- Around line 92-98: The MuiFormikUpload instance inside the
DocumentDownloadModule uses a hardcoded id ("document-module-upload") which will
duplicate across multiple modules; change the id to be unique per module by
deriving it from the module instance (e.g., include the module index, module id
prop, or reuse buildFieldName("file") as part of the id) so each MuiFormikUpload
has a distinct id attribute; update the id prop on the MuiFormikUpload in
page-template-modules-form.js accordingly and ensure any label/for references
use the same generated id.
- Around line 167-178: The InputLabel uses the wrong htmlFor value; change
htmlFor in the InputLabel surrounding the MuiFormikSelect to use
buildFieldName("file_type_id") instead of buildFieldName("max_file_size") so the
label correctly targets the select; update the InputLabel that wraps the
MuiFormikSelect (referencing buildFieldName and the file_type_id field name) to
restore proper label-input association for accessibility.
In
`@src/pages/sponsors/sponsor-pages-list-page/components/global-page/global-page-popup.js`:
- Around line 31-43: The Dialog currently passes the external onClose prop
directly which prevents resetting internal state; change the Dialog's onClose to
call the local handleClose function (the handler that resets stage and
selectedTemplates) instead of the external onClose, so backdrop clicks/Escape
trigger resetting internal state; keep using the external onClose (prop named
onClose) inside handleClose if it needs to notify parents after internal reset.
In `@src/pages/sponsors/sponsor-pages-list-page/index.js`:
- Around line 143-154: The Checkbox is uncontrolled because it lacks a checked
prop tied to the Redux state; update the Checkbox in the FormControlLabel to
pass checked={hideArchived} (ensure hideArchived is derived from Redux state in
this component) so the visual state matches the filter on initial render, and
keep using handleHideArchivedForms to dispatch/toggle the hideArchived value; if
hideArchived can be undefined ensure it is coerced to a boolean (e.g.,
!!hideArchived) before passing to checked.
- Around line 31-42: The component SponsorPagesListPage destructures
getSponsorForm but it isn’t wired to Redux; either add getSponsorForm to the
connect(...) mapDispatchToProps alongside getSponsorPages so the prop is
provided, or remove getSponsorForm from SponsorPagesListPage’s parameter list
and any usages (e.g., handleRowEdit) if the action isn’t implemented; ensure any
call sites like handleRowEdit reference the correctly connected action name.
In `@src/reducers/sponsors/sponsor-pages-list-reducer.js`:
- Around line 61-70: The reducer currently builds sponsorPages with module
counts using hardcoded kinds ("Upload"/"Download") causing
upload_mod/download_mod to be zero; update the modules.filter calls in the
sponsorPages mapping to use the PAGES_MODULE_KINDS constants (e.g.,
PAGES_MODULE_KINDS.DOCUMENT and PAGES_MODULE_KINDS.MEDIA) when computing those
counts, rename the fields from upload_mod/download_mod to document_mod/media_mod
to match the API constants, and propagate those new field names to the
corresponding table column and UI references so they consume document_mod and
media_mod instead of the old names.
🧹 Nitpick comments (15)
src/components/mui/formik-inputs/mui-formik-radio-group.js (1)
13-19: LGTM! Clean addition of configurable margin prop.The implementation correctly adds an optional
marginprop with a sensible default, preserving backward compatibility while enabling layout customization. This aligns with the PR-wide pattern of exposing more customization options on Formik inputs.Optional: Consider using
PropTypes.oneOfto restrict values to MUI's valid options:- margin: PropTypes.string, + margin: PropTypes.oneOf(["none", "dense", "normal"]),Also applies to: 25-25, 65-65
src/actions/page-template-actions.js (1)
145-160: Consider adding null-safety for the modules array.The
normalizeEntityfunction assumesentity.modulesis always a valid array. Ifentity.modulesisnullorundefined, the.map()call will throw a runtime error.Suggested defensive check
const normalizeEntity = (entity) => { const normalizedEntity = { ...entity }; - normalizedEntity.modules = entity.modules.map((module) => { + normalizedEntity.modules = (entity.modules || []).map((module) => { const normalizedModule = { ...module }; if (module.kind === PAGES_MODULE_KINDS.MEDIA && module.upload_deadline) { normalizedModule.upload_deadline = moment(module.upload_deadline).unix(); } delete normalizedModule._tempId; return normalizedModule; }); return normalizedEntity; };src/pages/sponsors/sponsor-pages-list-page/components/global-page/select-pages-dialog.js (3)
140-143: Hardcoded text should use i18n translation.The text "items selected" is hardcoded in English. For consistency with the rest of the component, this should use
T.translate().Suggested fix
<Grid2 size={4} sx={{ mt: 1 }}> - {selectedRows.length} items selected + {T.translate("sponsor_pages.global_page_popup.items_selected", { count: selectedRows.length })} </Grid2>
180-183: Consider adding PropTypes for Redux-injected props.The component receives several props from Redux (
pageTemplates,items,currentPage,term,order,orderDir,total,getPageTemplates) but onlyonCloseandonSaveare declared in PropTypes. Adding PropTypes for all props improves documentation and development-time validation.
38-40: AddgetPageTemplatesto useEffect dependency array.The effect references
getPageTemplatesbut the dependency array is empty. While this works because the function reference is stable (from Redux), adding it satisfies the exhaustive-deps rule and makes the intent clearer.Suggested fix
useEffect(() => { getPageTemplates("", 1, DEFAULT_PER_PAGE, "id", 1, true); - }, []); + }, [getPageTemplates]);src/components/mui/formik-inputs/mui-formik-upload.js (1)
125-128: Missingidin PropTypes.The
idprop is used (line 109) but not declared in PropTypes.Suggested fix
MuiFormikUpload.propTypes = { + id: PropTypes.string, name: PropTypes.string.isRequired, singleFile: PropTypes.bool };src/actions/sponsor-pages-actions.js (1)
133-133: Silent catch block may hide errors.The empty catch block swallows all errors silently. While the comment explains the intent to catch promise rejections, consider at minimum logging the error for debugging purposes.
Suggested fix
- .catch(() => {}); // need to catch promise reject + .catch((err) => { + console.error("cloneGlobalPage failed:", err); + });src/pages/sponsors/sponsor-pages-list-page/components/global-page/global-page-popup.js (1)
46-49: Consider addingcloneGlobalPageto PropTypes.The
cloneGlobalPageprop is injected byconnectbut not declared in PropTypes. While optional, documenting injected props improves maintainability.Proposed fix
GlobalPagePopup.propTypes = { open: PropTypes.bool.isRequired, - onClose: PropTypes.func.isRequired + onClose: PropTypes.func.isRequired, + cloneGlobalPage: PropTypes.func.isRequired };src/pages/sponsors-global/page-templates/page-template-popup.js (1)
160-162: Remove unnecessaryformikprop from PageModules.The
PageModulescomponent usesuseFormikContext()internally to access formik state (as seen in the relevant code snippet). Theformikprop passed here is unused.Proposed fix
<Box sx={{ py: 2 }}> - <PageModules formik={formik} /> + <PageModules /> </Box>src/pages/sponsors-global/page-templates/page-template-module-form.test.js (2)
64-64: Minor: Comment in Spanish should be in English for consistency.The comment "Mock DragAndDropList que captura onReorder" should be in English to maintain consistency with the rest of the codebase.
Suggested fix
-// Mock DragAndDropList que captura onReorder +// Mock DragAndDropList that captures onReorder
303-316: Consider: Tests rely on MUI implementation details.Tests use
.closest(".MuiAccordionSummary-root")which couples them to MUI's class naming. This could break if MUI changes its class names in a future version. Consider addingdata-testidattributes to theAccordionSummarycomponents in the actual implementation for more resilient testing.src/pages/sponsors/sponsor-pages-list-page/index.js (3)
45-47: Missing dependency inuseEffect.The
useEffecthook usesgetSponsorPagesbut doesn't include it in the dependency array. While this works becausegetSponsorPagesis a stable reference from Redux, ESLint'sreact-hooks/exhaustive-depsrule would flag this.Suggested fix
useEffect(() => { getSponsorPages(); - }, []); + }, [getSponsorPages]);
63-71: Stubbed handlers with console.log statements.
handleRowDeleteandhandleArchiveItemcontainconsole.logstatements and commented-out code. These appear to be work-in-progress placeholders. Consider adding TODO comments or removing the console.log before merging.Suggested change
const handleRowDelete = (itemId) => { - console.log("DELETE ITEM ID...", itemId); - // deleteSponsorForm(itemId); + // TODO: Implement delete functionality + // deleteSponsorPage(itemId); }; - const handleArchiveItem = (item) => console.log("archive ITEM...", item); - // item.is_archived - // ? unarchiveSponsorForm(item.id) - // : archiveSponsorForm(item.id); + const handleArchiveItem = (item) => { + // TODO: Implement archive functionality + // item.is_archived ? unarchiveSponsorPage(item.id) : archiveSponsorPage(item.id); + };
205-212: Commented code for FormPagePopup.The
FormPagePopupcomponent is commented out, indicating incomplete functionality. Consider adding a TODO comment to track this work item.src/i18n/en.json (1)
2644-2658: Minor: Inconsistent casing in translation value.Line 2648 has
"name": "name"(lowercase) while the corresponding column header on line 2632 has"name_column_label": "Name"(capitalized). The popup'snamefield label should likely be capitalized for consistency.Suggested fix
"global_page_popup": { "title": "Add Page Template", "items_selected": "items selected", "code": "Code", - "name": "name", + "name": "Name", "info_mod": "Info Mod",
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (18)
src/actions/page-template-actions.jssrc/actions/sponsor-pages-actions.jssrc/components/menu/index.jssrc/components/mui/formik-inputs/mui-formik-datepicker.jssrc/components/mui/formik-inputs/mui-formik-radio-group.jssrc/components/mui/formik-inputs/mui-formik-select.jssrc/components/mui/formik-inputs/mui-formik-upload.jssrc/i18n/en.jsonsrc/layouts/sponsor-layout.jssrc/pages/sponsors-global/page-templates/page-template-module-form.test.jssrc/pages/sponsors-global/page-templates/page-template-modules-form.jssrc/pages/sponsors-global/page-templates/page-template-popup.jssrc/pages/sponsors/sponsor-pages-list-page/components/global-page/global-page-popup.jssrc/pages/sponsors/sponsor-pages-list-page/components/global-page/select-pages-dialog.jssrc/pages/sponsors/sponsor-pages-list-page/index.jssrc/reducers/sponsors/sponsor-pages-list-reducer.jssrc/store.jssrc/utils/constants.js
🧰 Additional context used
🧬 Code graph analysis (8)
src/store.js (1)
src/reducers/sponsors/sponsor-pages-list-reducer.js (1)
sponsorPagesListReducer(33-83)
src/components/menu/index.js (1)
src/reducers/notes/notes-reducer.js (1)
summitId(48-48)
src/pages/sponsors-global/page-templates/page-template-popup.js (2)
src/pages/sponsors-global/page-templates/page-template-modules-form.js (2)
modules(200-200)PageModules(198-343)src/utils/constants.js (4)
PAGES_MODULE_KINDS(245-249)PAGES_MODULE_KINDS(245-249)PAGE_MODULES_MEDIA_TYPES(251-254)PAGE_MODULES_MEDIA_TYPES(251-254)
src/components/mui/formik-inputs/mui-formik-select.js (6)
src/components/mui/formik-inputs/mui-formik-datepicker.js (1)
field(9-9)src/components/mui/formik-inputs/mui-formik-upload.js (1)
field(14-14)src/components/mui/formik-inputs/mui-formik-textfield.js (1)
field(7-7)src/components/mui/formik-inputs/sponsorship-input-mui.js (2)
field(31-31)field(37-37)src/components/mui/formik-inputs/mui-formik-checkbox.js (1)
field(12-12)src/components/mui/formik-inputs/company-input-mui.js (2)
field(32-32)field(38-38)
src/actions/page-template-actions.js (1)
src/utils/constants.js (2)
PAGES_MODULE_KINDS(245-249)PAGES_MODULE_KINDS(245-249)
src/components/mui/formik-inputs/mui-formik-upload.js (1)
src/utils/constants.js (6)
MAX_INVENTORY_IMAGE_UPLOAD_SIZE(190-190)MAX_INVENTORY_IMAGE_UPLOAD_SIZE(190-190)MAX_INVENTORY_IMAGES_UPLOAD_QTY(191-191)MAX_INVENTORY_IMAGES_UPLOAD_QTY(191-191)ALLOWED_INVENTORY_IMAGE_FORMATS(192-192)ALLOWED_INVENTORY_IMAGE_FORMATS(192-192)
src/pages/sponsors-global/page-templates/page-template-modules-form.js (3)
src/utils/constants.js (4)
PAGE_MODULES_MEDIA_TYPES(251-254)PAGE_MODULES_MEDIA_TYPES(251-254)PAGES_MODULE_KINDS(245-249)PAGES_MODULE_KINDS(245-249)src/components/mui/showConfirmDialog.js (1)
showConfirmDialog(5-42)src/components/mui/dnd-list.js (1)
DragAndDropList(16-72)
src/reducers/sponsors/sponsor-pages-list-reducer.js (1)
src/actions/sponsor-pages-actions.js (4)
REQUEST_SPONSOR_PAGES(31-31)REQUEST_SPONSOR_PAGES(31-31)RECEIVE_SPONSOR_PAGES(32-32)RECEIVE_SPONSOR_PAGES(32-32)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (6)
- GitHub Check: build
- GitHub Check: build
- GitHub Check: build
- GitHub Check: build
- GitHub Check: build
- GitHub Check: build
🔇 Additional comments (22)
src/components/mui/formik-inputs/mui-formik-select.js (2)
1-12: LGTM!The new imports for
IconButtonandInputLabelare appropriate for the added label and clearable functionality.
29-30: LGTM!The
hasValueguard correctly checks for non-empty values, handling empty string,undefined, andnullcases appropriately.src/utils/constants.js (1)
244-254: LGTM!The new constants are well-organized and follow the existing patterns in this file.
PAGES_MODULE_KINDSandPAGE_MODULES_MEDIA_TYPESprovide clear, centralized definitions for module kinds and media types used throughout the sponsor pages feature.src/actions/page-template-actions.js (1)
14-33: LGTM!The new imports for
moment-timezoneandPAGES_MODULE_KINDSare correctly placed and support the enhanced module normalization logic.src/actions/sponsor-pages-actions.js (1)
68-72: Verify the filter logic for sponsorship types.The filter uses
sponsorship_type_id_not_inwhich appears to exclude rather than include the specified sponsorship types. Confirm this is the intended behavior for the use case.src/components/mui/formik-inputs/mui-formik-upload.js (1)
76-91: Verify the property name of the imageFile parameter passed by UploadInputV2's onRemove callback.The filter on line 84 compares
i.filename !== imageFile.name, but without access to the external UploadInputV2 library (fromopenstack-uicore-foundation), it cannot be definitively confirmed whetherimageFile.nameis correct. Cross-checking with similar code in inventory-item-form.js and form-template-form.js shows identical patterns, but this could indicate either consistent behavior or a systemic issue. Confirm the property name that UploadInputV2 passes to the onRemove callback—if it's notname, the filter will fail silently and files won't be removed from the array.src/reducers/sponsors/sponsor-pages-list-reducer.js (2)
21-31: LGTM!The DEFAULT_STATE structure is well-defined with appropriate defaults for pagination, sorting, and filtering.
36-52: LGTM!Proper handling of state reset on summit change/logout and request state management with cleared data during loading.
src/store.js (2)
170-170: LGTM!Import correctly added for the new sponsor pages list reducer.
254-254: LGTM!New state slice properly registered following the existing naming conventions and placed logically with other sponsor-related state.
src/pages/sponsors/sponsor-pages-list-page/components/global-page/global-page-popup.js (1)
25-29: LGTM!Good use of
.finally()to ensure cleanup regardless of success or failure.src/layouts/sponsor-layout.js (1)
67-87: LGTM!The route structure correctly follows the existing pattern with proper breadcrumb integration and nested Switch/Route setup.
src/pages/sponsors-global/page-templates/page-template-popup.js (3)
33-41: LGTM!Good extraction of common module creation logic into
addModulehelper. The temporary ID and order assignment pattern is clean.
43-70: LGTM!Module handlers properly initialize all required fields for each module type using the extracted
addModulehelper and imported constants.
72-89: LGTM!Good approach to normalize module ordering on submit by mapping indices to
custom_order, ensuring consistent ordering regardless of user reordering during editing.src/components/menu/index.js (1)
247-251: LGTM!The new
sponsor_pagesmenu item follows the established pattern for other sponsor-related menu items, with appropriate routing and access control viaadmin-sponsors.src/pages/sponsors-global/page-templates/page-template-module-form.test.js (1)
83-116: LGTM!The test helpers
renderWithFormikandcreateModuleare well-designed and provide good isolation for testing the PageModules component. ThebeforeEachblock properly resets state between tests.src/pages/sponsors-global/page-templates/page-template-modules-form.js (3)
240-243: Consider: Module ordering may have gaps after deletion.After deleting a module, the
custom_ordervalues of remaining modules are not recalculated. For example, if modules have orders [0, 1, 2] and module at index 1 is deleted, the remaining modules will have orders [0, 2]. This may or may not be intentional depending on how the backend handles ordering.Verify if the backend expects contiguous
custom_ordervalues or if gaps are acceptable. If contiguous values are required, consider recalculating orders after deletion:if (isConfirmed) { const updated = modules .filter((_, i) => i !== index) .map((m, i) => ({ ...m, custom_order: i })); setFieldValue(name, updated); }
198-211: LGTM!The auto-scroll functionality using refs and
useEffectis well-implemented. It correctly detects when a new module is added and scrolls to make it visible.
319-342: LGTM!The main render logic correctly handles the empty state, renders the DragAndDropList with appropriate configuration, and includes the scroll target element.
src/i18n/en.json (2)
2626-2643: LGTM!The new
sponsor_pagestranslation object is well-structured with appropriate keys for the list page, column labels, filters, and empty state message.
3950-3964: LGTM!The new module-related translation keys under
page_template_list.page_crudare comprehensive and cover all the module types (Info, Document, Media) and their fields.
✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.
| export const cloneGlobalPage = | ||
| (pagesIds, sponsorIds, allSponsors) => async (dispatch, getState) => { | ||
| const { currentSummitState } = getState(); | ||
| const accessToken = await getAccessTokenSafely(); | ||
| const { currentSummit } = currentSummitState; | ||
|
|
||
| dispatch(startLoading()); | ||
|
|
||
| const params = { | ||
| access_token: accessToken | ||
| }; | ||
|
|
||
| const normalizedEntity = { | ||
| page_template_ids: pagesIds, | ||
| sponsorship_types: sponsorIds, | ||
| apply_to_all_types: allSponsors | ||
| }; | ||
|
|
||
| if (allSponsors) { | ||
| delete normalizedEntity.sponsorship_types; | ||
| } | ||
|
|
||
| return postRequest( | ||
| null, | ||
| createAction(GLOBAL_PAGE_CLONED), | ||
| `${window.SPONSOR_PAGES_API_URL}/api/v1/summits/${currentSummit.id}/show-pages/clone`, | ||
| normalizedEntity, | ||
| snackbarErrorHandler | ||
| )(params)(dispatch) | ||
| .then(() => { | ||
| dispatch(getSponsorForms()); | ||
| dispatch( | ||
| snackbarSuccessHandler({ | ||
| title: T.translate("general.success"), | ||
| html: T.translate("sponsor_pages.global_page_popup.success") | ||
| }) | ||
| ); | ||
| }) | ||
| .catch(() => {}); // need to catch promise reject |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing stopLoading() dispatch in cloneGlobalPage.
startLoading() is dispatched at line 101, but stopLoading() is never called. This will leave the loading state active indefinitely after the clone operation completes (success or failure).
Suggested fix
return postRequest(
null,
createAction(GLOBAL_PAGE_CLONED),
`${window.SPONSOR_PAGES_API_URL}/api/v1/summits/${currentSummit.id}/show-pages/clone`,
normalizedEntity,
snackbarErrorHandler
)(params)(dispatch)
.then(() => {
dispatch(getSponsorForms());
dispatch(
snackbarSuccessHandler({
title: T.translate("general.success"),
html: T.translate("sponsor_pages.global_page_popup.success")
})
);
})
- .catch(() => {}); // need to catch promise reject
+ .catch(() => {})
+ .finally(() => {
+ dispatch(stopLoading());
+ });
};🤖 Prompt for AI Agents
In `@src/actions/sponsor-pages-actions.js` around lines 95 - 133, The
cloneGlobalPage action dispatches startLoading() but never dispatches
stopLoading(), leaving the loading state active; update cloneGlobalPage to
dispatch stopLoading() in both the success path (before/after dispatching
getSponsorForms() and snackbarSuccessHandler) and in the catch/failure path
(before handling errors via snackbarErrorHandler) so that stopLoading() is
always called regardless of postRequest resolving or rejecting; locate the
postRequest(...) promise chain in cloneGlobalPage and add
dispatch(stopLoading()) in both the .then and .catch handlers (or use finally)
to guarantee loading is cleared.
| .then(() => { | ||
| dispatch(getSponsorForms()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getSponsorForms is not imported - this will cause a runtime error.
The function getSponsorForms() is called but never imported. This will throw a ReferenceError at runtime when cloneGlobalPage succeeds.
Suggested fix
Add the missing import at the top of the file:
+import { getSponsorForms } from "./sponsor-actions";Or, if the intent was to refresh sponsor pages instead:
.then(() => {
- dispatch(getSponsorForms());
+ dispatch(getSponsorPages());📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| .then(() => { | |
| dispatch(getSponsorForms()); | |
| .then(() => { | |
| dispatch(getSponsorPages()); |
🤖 Prompt for AI Agents
In `@src/actions/sponsor-pages-actions.js` around lines 124 - 125, The call to
getSponsorForms() inside the cloneGlobalPage promise chain will throw because
getSponsorForms is not imported; fix this by adding an import for
getSponsorForms at the top of the file from the module that exports it (the same
module where sponsor form actions live) and keep the dispatch(getSponsorForms())
call, or if the intent was to refresh sponsor pages instead, replace that call
with the correct exported action (e.g., dispatch(getSponsorPages()) )—ensure the
chosen function is imported and referenced (symbols: getSponsorForms,
cloneGlobalPage, dispatch).
| {label && ( | ||
| <InputLabel htmlFor={name} id={`${name}-label`} shrink={hasValue}> | ||
| {label} | ||
| </InputLabel> | ||
| )} | ||
| <Select | ||
| name={name} | ||
| // eslint-disable-next-line react/jsx-props-no-spreading | ||
| {...field} | ||
| labelId={`${name}-label`} | ||
| label={label} | ||
| notched={hasValue} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
cat -n src/components/mui/formik-inputs/mui-formik-select.jsRepository: fntechgit/summit-admin
Length of output: 2702
🏁 Script executed:
rg "MuiFormikSelect" --type js --type jsx -A 3 -B 1 | head -100Repository: fntechgit/summit-admin
Length of output: 93
🏁 Script executed:
rg "MuiFormikSelect" -A 3 -B 1 | head -150Repository: fntechgit/summit-admin
Length of output: 12188
🏁 Script executed:
rg "MuiFormikSelect" -B 5 -A 8 "src/components/mui/formik-inputs/additional-input/additional-input.js"Repository: fntechgit/summit-admin
Length of output: 1516
Label and placeholder text may visually overlap when no value is selected.
When displayEmpty is true and a placeholder is provided (currently used in src/components/mui/formik-inputs/additional-input/additional-input.js), the InputLabel will remain un-shrunk (inside the select box) while the placeholder text displays in the same area. This causes visual overlap.
The label should always shrink when a placeholder is present:
Suggested fix
const hasValue =
field.value !== "" && field.value !== undefined && field.value !== null;
+ const shouldShrink = hasValue || Boolean(placeholder);
return (
<FormControl fullWidth error={meta.touched && Boolean(meta.error)}>
{label && (
- <InputLabel htmlFor={name} id={`${name}-label`} shrink={hasValue}>
+ <InputLabel htmlFor={name} id={`${name}-label`} shrink={shouldShrink}>
{label}
</InputLabel>
)}
<Select
name={name}
// eslint-disable-next-line react/jsx-props-no-spreading
{...field}
labelId={`${name}-label`}
label={label}
- notched={hasValue}
+ notched={shouldShrink}🤖 Prompt for AI Agents
In `@src/components/mui/formik-inputs/mui-formik-select.js` around lines 34 - 45,
The label can overlap the placeholder because hasValue only reflects a selected
value; update the hasValue logic in the component that renders InputLabel and
Select so it treats a provided placeholder (and displayEmpty=true) as a value —
e.g., compute hasValue = Boolean(field.value) || (displayEmpty &&
Boolean(placeholder)) — then continue using hasValue for InputLabel's shrink and
Select's notched props (symbols: InputLabel, Select, hasValue, placeholder,
displayEmpty, field).
| const MuiFormikUpload = ({ id, name, onImageDeleted, singleFile = false }) => { | ||
| const [field, meta, helpers] = useField(name); | ||
|
|
||
| console.log("images: ", field.value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove debug console.log statement.
This debug statement should be removed before merging to production.
Suggested fix
- console.log("images: ", field.value);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| console.log("images: ", field.value); |
🤖 Prompt for AI Agents
In `@src/components/mui/formik-inputs/mui-formik-upload.js` at line 16, Remove the
debug console.log statement currently logging "images: " and field.value inside
the MuiFormikUpload component; delete the line console.log("images: ",
field.value) (or replace it with a proper debug-level logger if persistent
logging is required) so no console output remains in production.
| filename: response.name | ||
| }; | ||
| helpers.setValue([...field.value, image]); | ||
| console.log("CHJECK RESPONSE", response); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove debug console.log with typo.
Debug statement with typo ("CHJECK" → "CHECK") should be removed before merging.
Suggested fix
- console.log("CHJECK RESPONSE", response);📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| console.log("CHJECK RESPONSE", response); |
🤖 Prompt for AI Agents
In `@src/components/mui/formik-inputs/mui-formik-upload.js` at line 65, Remove the
debug console.log in the UploadFormik component (the line logging "CHJECK
RESPONSE" in mui-formik-upload.js); delete that console.log statement (or
replace it with a proper logger call without the typo if intentional) so no
stray debug output remains in the upload handling code.
| <Grid2 size={12}> | ||
| <InputLabel htmlFor={buildFieldName("max_file_size")}> | ||
| {T.translate("page_template_list.page_crud.description")} | ||
| </InputLabel> | ||
| <MuiFormikTextField | ||
| name={buildFieldName("description")} | ||
| fullWidth | ||
| multiline | ||
| margin="none" | ||
| rows={2} | ||
| /> | ||
| </Grid2> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
htmlFor attribute points to wrong field name.
The InputLabel on line 183 has htmlFor={buildFieldName("max_file_size")} but the associated field is description. This is another copy-paste error affecting accessibility.
Suggested fix
<Grid2 size={12}>
- <InputLabel htmlFor={buildFieldName("max_file_size")}>
+ <InputLabel htmlFor={buildFieldName("description")}>
{T.translate("page_template_list.page_crud.description")}
</InputLabel>
<MuiFormikTextField
name={buildFieldName("description")}
fullWidth
multiline
margin="none"
rows={2}
/>
</Grid2>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Grid2 size={12}> | |
| <InputLabel htmlFor={buildFieldName("max_file_size")}> | |
| {T.translate("page_template_list.page_crud.description")} | |
| </InputLabel> | |
| <MuiFormikTextField | |
| name={buildFieldName("description")} | |
| fullWidth | |
| multiline | |
| margin="none" | |
| rows={2} | |
| /> | |
| </Grid2> | |
| <Grid2 size={12}> | |
| <InputLabel htmlFor={buildFieldName("description")}> | |
| {T.translate("page_template_list.page_crud.description")} | |
| </InputLabel> | |
| <MuiFormikTextField | |
| name={buildFieldName("description")} | |
| fullWidth | |
| multiline | |
| margin="none" | |
| rows={2} | |
| /> | |
| </Grid2> |
🤖 Prompt for AI Agents
In `@src/pages/sponsors-global/page-templates/page-template-modules-form.js`
around lines 182 - 193, InputLabel's htmlFor is incorrectly targeting
buildFieldName("max_file_size") while the actual form control is
MuiFormikTextField with name buildFieldName("description"); update the
InputLabel so htmlFor uses buildFieldName("description") to match the
MuiFormikTextField name and restore proper accessibility (locate the InputLabel
and adjust the buildFieldName argument from "max_file_size" to "description").
| return ( | ||
| <Dialog open={open} onClose={onClose} maxWidth={dialogSize} fullWidth> | ||
| {stage === "pages" && ( | ||
| <SelectPagesDialog | ||
| onSave={handleOnSelectTemplates} | ||
| onClose={handleClose} | ||
| /> | ||
| )} | ||
| {stage === "sponsorships" && ( | ||
| <SelectSponsorshipsDialog onSave={handleOnSave} onClose={handleClose} /> | ||
| )} | ||
| </Dialog> | ||
| ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use handleClose for Dialog's onClose prop to reset internal state.
The Dialog's onClose uses onClose directly instead of handleClose. When the user closes the dialog via backdrop click or escape key, the internal state (stage, selectedTemplates) won't be reset, potentially causing stale state on next open.
Proposed fix
- <Dialog open={open} onClose={onClose} maxWidth={dialogSize} fullWidth>
+ <Dialog open={open} onClose={handleClose} maxWidth={dialogSize} fullWidth>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| return ( | |
| <Dialog open={open} onClose={onClose} maxWidth={dialogSize} fullWidth> | |
| {stage === "pages" && ( | |
| <SelectPagesDialog | |
| onSave={handleOnSelectTemplates} | |
| onClose={handleClose} | |
| /> | |
| )} | |
| {stage === "sponsorships" && ( | |
| <SelectSponsorshipsDialog onSave={handleOnSave} onClose={handleClose} /> | |
| )} | |
| </Dialog> | |
| ); | |
| return ( | |
| <Dialog open={open} onClose={handleClose} maxWidth={dialogSize} fullWidth> | |
| {stage === "pages" && ( | |
| <SelectPagesDialog | |
| onSave={handleOnSelectTemplates} | |
| onClose={handleClose} | |
| /> | |
| )} | |
| {stage === "sponsorships" && ( | |
| <SelectSponsorshipsDialog onSave={handleOnSave} onClose={handleClose} /> | |
| )} | |
| </Dialog> | |
| ); |
🤖 Prompt for AI Agents
In
`@src/pages/sponsors/sponsor-pages-list-page/components/global-page/global-page-popup.js`
around lines 31 - 43, The Dialog currently passes the external onClose prop
directly which prevents resetting internal state; change the Dialog's onClose to
call the local handleClose function (the handler that resets stage and
selectedTemplates) instead of the external onClose, so backdrop clicks/Escape
trigger resetting internal state; keep using the external onClose (prop named
onClose) inside handleClose if it needs to notify parents after internal reset.
| const SponsorPagesListPage = ({ | ||
| sponsorPages, | ||
| currentPage, | ||
| perPage, | ||
| term, | ||
| order, | ||
| orderDir, | ||
| hideArchived, | ||
| totalCount, | ||
| getSponsorPages, | ||
| getSponsorForm | ||
| }) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getSponsorForm is destructured but not connected via Redux.
The getSponsorForm action is destructured from props on line 41 but is not included in the connect call on lines 221-223. This will cause getSponsorForm to be undefined when handleRowEdit is called, resulting in a runtime error.
Suggested fix
Either add getSponsorForm to the connect call:
-export default connect(mapStateToProps, {
- getSponsorPages
+import { getSponsorPages, getSponsorForm } from "../../../actions/sponsor-pages-actions";
+
+export default connect(mapStateToProps, {
+ getSponsorPages,
+ getSponsorForm
})(SponsorPagesListPage);Or remove it from the destructured props if not yet implemented.
🤖 Prompt for AI Agents
In `@src/pages/sponsors/sponsor-pages-list-page/index.js` around lines 31 - 42,
The component SponsorPagesListPage destructures getSponsorForm but it isn’t
wired to Redux; either add getSponsorForm to the connect(...) mapDispatchToProps
alongside getSponsorPages so the prop is provided, or remove getSponsorForm from
SponsorPagesListPage’s parameter list and any usages (e.g., handleRowEdit) if
the action isn’t implemented; ensure any call sites like handleRowEdit reference
the correctly connected action name.
| <FormControlLabel | ||
| control={ | ||
| <Checkbox | ||
| onChange={handleHideArchivedForms} | ||
| inputProps={{ | ||
| "aria-label": T.translate("sponsor_pages.hide_archived") | ||
| }} | ||
| /> | ||
| } | ||
| label={T.translate("sponsor_pages.hide_archived")} | ||
| /> | ||
| </FormGroup> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Checkbox is uncontrolled - missing checked prop.
The "Hide archived" checkbox doesn't have a checked prop bound to the hideArchived state from Redux. This means the checkbox visual state won't reflect the actual filter state, especially on initial render.
Suggested fix
<FormControlLabel
control={
<Checkbox
+ checked={hideArchived}
onChange={handleHideArchivedForms}
inputProps={{
"aria-label": T.translate("sponsor_pages.hide_archived")
}}
/>
}
label={T.translate("sponsor_pages.hide_archived")}
/>📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <FormControlLabel | |
| control={ | |
| <Checkbox | |
| onChange={handleHideArchivedForms} | |
| inputProps={{ | |
| "aria-label": T.translate("sponsor_pages.hide_archived") | |
| }} | |
| /> | |
| } | |
| label={T.translate("sponsor_pages.hide_archived")} | |
| /> | |
| </FormGroup> | |
| <FormControlLabel | |
| control={ | |
| <Checkbox | |
| checked={hideArchived} | |
| onChange={handleHideArchivedForms} | |
| inputProps={{ | |
| "aria-label": T.translate("sponsor_pages.hide_archived") | |
| }} | |
| /> | |
| } | |
| label={T.translate("sponsor_pages.hide_archived")} | |
| /> |
🤖 Prompt for AI Agents
In `@src/pages/sponsors/sponsor-pages-list-page/index.js` around lines 143 - 154,
The Checkbox is uncontrolled because it lacks a checked prop tied to the Redux
state; update the Checkbox in the FormControlLabel to pass
checked={hideArchived} (ensure hideArchived is derived from Redux state in this
component) so the visual state matches the filter on initial render, and keep
using handleHideArchivedForms to dispatch/toggle the hideArchived value; if
hideArchived can be undefined ensure it is coerced to a boolean (e.g.,
!!hideArchived) before passing to checked.
| const sponsorPages = payload.response.data.map((a) => ({ | ||
| id: a.id, | ||
| code: a.code, | ||
| name: a.name, | ||
| tier: a.sponsorship_types.map((s) => s.name).join(", "), | ||
| info_mod: a.modules.filter((m) => m.kind === "Info").length, | ||
| upload_mod: a.modules.filter((m) => m.kind === "Upload").length, | ||
| download_mod: a.modules.filter((m) => m.kind === "Download").length, | ||
| is_archived: a.is_archived | ||
| })); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# First, find the PAGES_MODULE_KINDS constant definition
rg -n "PAGES_MODULE_KINDS" --type=js -A 5 -B 2Repository: fntechgit/summit-admin
Length of output: 26166
🏁 Script executed:
#!/bin/bash
# Search for module kind string values used in filtering/comparisons
rg -n "kind\s*[=!:]\s*['\"]" --type=js | head -50Repository: fntechgit/summit-admin
Length of output: 48
🏁 Script executed:
#!/bin/bash
# Look for module kind references in API responses or types
rg -n "\"kind\":|'kind':" --type=js -A 2 | head -100Repository: fntechgit/summit-admin
Length of output: 48
🏁 Script executed:
#!/bin/bash
# Check the sponsor pages file structure for context
fd "sponsor" --type=f -e js | head -20Repository: fntechgit/summit-admin
Length of output: 1011
🏁 Script executed:
#!/bin/bash
# Check the actual sponsor pages list reducer file
cat -n src/reducers/sponsors/sponsor-pages-list-reducer.js | sed -n '55,75p'Repository: fntechgit/summit-admin
Length of output: 865
🏁 Script executed:
#!/bin/bash
# Also check what the property names should be and any usages of these properties
rg -n "upload_mod|download_mod|document_mod|media_mod" --type=jsRepository: fntechgit/summit-admin
Length of output: 2388
🏁 Script executed:
#!/bin/bash
# Look for API response examples or test data
rg -n "kind.*:.*['\"]" src/pages/sponsors-global/page-templates/page-template-module-form.test.js -A 2 | head -30Repository: fntechgit/summit-admin
Length of output: 48
🏁 Script executed:
#!/bin/bash
# Search for sponsor pages API examples in actions or tests
fd "sponsor-pages" --type=f -e js | xargs rg -l "modules"Repository: fntechgit/summit-admin
Length of output: 117
🏁 Script executed:
#!/bin/bash
# Check page-template-list-reducer for comparison
cat -n src/reducers/sponsors_inventory/page-template-list-reducer.js | sed -n '70,85p'Repository: fntechgit/summit-admin
Length of output: 728
🏁 Script executed:
#!/bin/bash
# Check if there are any test fixtures or mock data for sponsor pages
fd "sponsor-pages" --type=f -e test.js | xargs cat | head -200Repository: fntechgit/summit-admin
Length of output: 48
🏁 Script executed:
#!/bin/bash
# Look for API response mock data in sponsor pages actions
rg -n "modules.*\[" src/actions/sponsor-pages-actions.js -A 5 | head -50Repository: fntechgit/summit-admin
Length of output: 48
🏁 Script executed:
#!/bin/bash
# Check if "Upload" and "Download" strings appear anywhere else as module kinds
rg -n '"Upload"|"Download"' --type=js | grep -i moduleRepository: fntechgit/summit-admin
Length of output: 605
🏁 Script executed:
#!/bin/bash
# Check the UI components that use these properties to understand intent
rg -n "upload_mod|download_mod" src/pages/sponsors/sponsor-pages-list-page/index.js -B 2 -A 2Repository: fntechgit/summit-admin
Length of output: 387
🏁 Script executed:
#!/bin/bash
# Check what the actual API might return - look at sponsor-pages-actions
cat src/actions/sponsor-pages-actions.js | head -100Repository: fntechgit/summit-admin
Length of output: 3182
🏁 Script executed:
#!/bin/bash
# Look for API response examples, mocks, or fixtures
fd . --type=f -e json | xargs rg -l "modules" | head -10Repository: fntechgit/summit-admin
Length of output: 95
🏁 Script executed:
#!/bin/bash
# Search for test data or fixtures related to sponsor pages
find . -path ./node_modules -prune -o -type f \( -name "*.test.js" -o -name "*.spec.js" -o -name "*fixture*" -o -name "*mock*" \) -print | xargs rg -l "sponsor.*page" 2>/dev/null | head -10Repository: fntechgit/summit-admin
Length of output: 48
🏁 Script executed:
#!/bin/bash
# Check if there's any documentation or comments about module kinds
rg -n "Info|Upload|Download" src/actions/sponsor-pages-actions.js -B 2 -A 2Repository: fntechgit/summit-admin
Length of output: 48
🏁 Script executed:
#!/bin/bash
# Check if the API endpoint documentation or swagger is available
fd . --type=f \( -name "swagger*" -o -name "openapi*" -o -name "*.yaml" -o -name "*.yml" \) 2>/dev/null | head -10Repository: fntechgit/summit-admin
Length of output: 48
🏁 Script executed:
#!/bin/bash
# Check i18n for module kind labels
rg -n "upload_mod|download_mod|document_module|media_module|Info|Upload|Download" src/i18n/en.json | head -30Repository: fntechgit/summit-admin
Length of output: 1625
🏁 Script executed:
#!/bin/bash
# Check if there's backend API documentation or type definitions
fd . --type=f -e ts | xargs rg -l "modules|kind" 2>/dev/null | head -10Repository: fntechgit/summit-admin
Length of output: 505
🏁 Script executed:
#!/bin/bash
# Look at the complete page-template-list-reducer file structure for comparison
cat -n src/reducers/sponsors_inventory/page-template-list-reducer.js | head -100Repository: fntechgit/summit-admin
Length of output: 3581
🏁 Script executed:
#!/bin/bash
# Verify what properties are accessed from sponsorPages in the UI
rg -n "sponsorPages" src/pages/sponsors/sponsor-pages-list-page/index.js -A 3 -B 3 | head -50Repository: fntechgit/summit-admin
Length of output: 863
🏁 Script executed:
#!/bin/bash
# Check if there are any actual API examples with modules data structure
rg -n "modules.*\[" --type=js -A 10 | grep -A 10 "kind"Repository: fntechgit/summit-admin
Length of output: 4340
Fix module kind filtering to use constants instead of hardcoded strings.
The reducer filters modules using hardcoded strings "Upload" and "Download", but the PAGES_MODULE_KINDS constant defines the actual API values as "Document" and "Media". This mismatch causes upload_mod and download_mod to always be 0.
Update to use the constants for consistency and correctness:
Suggested fix
+import { PAGES_MODULE_KINDS } from "../../utils/constants";
...
- info_mod: a.modules.filter((m) => m.kind === "Info").length,
- upload_mod: a.modules.filter((m) => m.kind === "Upload").length,
- download_mod: a.modules.filter((m) => m.kind === "Download").length,
+ info_mod: a.modules.filter((m) => m.kind === PAGES_MODULE_KINDS.INFO).length,
+ document_mod: a.modules.filter((m) => m.kind === PAGES_MODULE_KINDS.DOCUMENT).length,
+ media_mod: a.modules.filter((m) => m.kind === PAGES_MODULE_KINDS.MEDIA).length,Note: Also update the corresponding table columns and UI references to use document_mod and media_mod instead of upload_mod and download_mod.
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| const sponsorPages = payload.response.data.map((a) => ({ | |
| id: a.id, | |
| code: a.code, | |
| name: a.name, | |
| tier: a.sponsorship_types.map((s) => s.name).join(", "), | |
| info_mod: a.modules.filter((m) => m.kind === "Info").length, | |
| upload_mod: a.modules.filter((m) => m.kind === "Upload").length, | |
| download_mod: a.modules.filter((m) => m.kind === "Download").length, | |
| is_archived: a.is_archived | |
| })); | |
| const sponsorPages = payload.response.data.map((a) => ({ | |
| id: a.id, | |
| code: a.code, | |
| name: a.name, | |
| tier: a.sponsorship_types.map((s) => s.name).join(", "), | |
| info_mod: a.modules.filter((m) => m.kind === PAGES_MODULE_KINDS.INFO).length, | |
| document_mod: a.modules.filter((m) => m.kind === PAGES_MODULE_KINDS.DOCUMENT).length, | |
| media_mod: a.modules.filter((m) => m.kind === PAGES_MODULE_KINDS.MEDIA).length, | |
| is_archived: a.is_archived | |
| })); |
🤖 Prompt for AI Agents
In `@src/reducers/sponsors/sponsor-pages-list-reducer.js` around lines 61 - 70,
The reducer currently builds sponsorPages with module counts using hardcoded
kinds ("Upload"/"Download") causing upload_mod/download_mod to be zero; update
the modules.filter calls in the sponsorPages mapping to use the
PAGES_MODULE_KINDS constants (e.g., PAGES_MODULE_KINDS.DOCUMENT and
PAGES_MODULE_KINDS.MEDIA) when computing those counts, rename the fields from
upload_mod/download_mod to document_mod/media_mod to match the API constants,
and propagate those new field names to the corresponding table column and UI
references so they consume document_mod and media_mod instead of the old names.
ref:
https://app.clickup.com/t/86b7ubdfg
https://app.clickup.com/t/86b79918r
https://app.clickup.com/t/86b79918z
Summary by CodeRabbit
New Features
Improvements
Tests
✏️ Tip: You can customize this high-level summary in your review settings.